{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# পর্ব ১২: এনক্রিপ্টেড ডেটা দিয়ে এনক্রিপ্টেড এনএন (NN) ট্রেইন করা (Train an Encrypted NN on Encrypted Data)\n",
    "এই নোটবুকে আমরা নিউরাল নেটওয়ার্ক ট্রেইনিং ও প্রেডিকশানের ব্যাপারে এযাবত যা কিছু শিখেছি তার সমস্ত কিছু প্রয়োগ করে এনক্রিপ্টেড ডেটা দিয়ে এনক্রিপ্টেড মডেল ট্রেইন করব।\n",
    "\n",
    "বিশেষত, আমরা আমাদের কাস্টম অটোগ্রাড ইঞ্জিন উপস্থাপন করব যা এনক্রিপ্টেড ডেটার উপর কাজ করে।\n",
    "\n",
    "লেখকগণ:\n",
    "- Andrew Trask - Twitter: [@iamtrask](https://twitter.com/iamtrask)\n",
    "- Jason Paumier - Github: [@Jasopaum](https://github.com/Jasopaum)\n",
    "- Théo Ryffel - Twitter: [@theoryffel](https://twitter.com/theoryffel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "অনুবাদক:\n",
    "\n",
    "- Sourav Das - Twitter: [@adventuroussrv](https://twitter.com/adventuroussrv)\n",
    "- Zarreen Reza - Twitter: [@zarreennreza](https://twitter.com/zarreennreza)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ধাপ-১ঃ ওয়ার্কার ও খেলনা ডেটা তৈরি (Create Workers and Toy Data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "import syft as sy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set everything up\n",
    "hook = sy.TorchHook(torch) \n",
    "\n",
    "alice = sy.VirtualWorker(id=\"alice\", hook=hook)\n",
    "bob = sy.VirtualWorker(id=\"bob\", hook=hook)\n",
    "james = sy.VirtualWorker(id=\"james\", hook=hook)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# A Toy Dataset\n",
    "data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]])\n",
    "target = torch.tensor([[0],[0],[1],[1.]])\n",
    "\n",
    "# A Toy Model\n",
    "class Net(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        self.fc1 = nn.Linear(2, 2)\n",
    "        self.fc2 = nn.Linear(2, 1)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.fc1(x)\n",
    "        x = F.relu(x)\n",
    "        x = self.fc2(x)\n",
    "        return x\n",
    "model = Net()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ধাপ-২ঃ মডেল ও ডেটা এনক্রিপ্ট করণ (Encrypt the Model and Data)\n",
    "Multi-Party Computation\n",
    "এনক্রিপ্শান দুই ধাপে সম্পন্ন হয়। যেহেতু Secure Multi-Party Computation শুধুমাত্র পূর্ণসংখ্যার উপর কাজ করে, তাই দশমিকপূর্ণ সংখ্যার (যেমন weights ও activations) উপর কাজ করার জন্য  আমাদের আগে সকল সংখ্যাকে Fixed Precision দিয়ে এনকোড করতে হবে, যা আমাদের কয়েক দশমিক পর্যন্ত নির্ভুল মান দিবে। আমরা .fix_precision() কল করে এটা করতে পারি। \n",
    "\n",
    "তারপর আমরা অন্য ডেমোগুলোর ক্ষেত্রে যেভাবে করেছি, সেভাবে  .share() কল করে ডেটাগুলো Alice ও Bob এর মধ্যে পরস্পর শেয়ার করে এনক্রিপট করতে পারি। এখানে লক্ষণীয় যে, আমরা  requires_grad এর মান True সেট করে দিলে তা এনক্রিপ্টেড ডেটার জন্য একটি বিশেষ অটোগ্রেড মেথড যুক্ত করবে। স্বাভাবিকভাবেই, যেহেতু Secure Multi-Party Computation দশমিক সংখ্যার উপর কাজ করেনা, তাই এক্ষেত্রে সাধারণ PyTorch অটোগ্রেড মেথড করা যাবেনা। সুতরাং, আমাদের একটি বিশেষ AutogradTensor নোড যুক্ত করে backpropagation এর জন্য gradient graph গণনা করতে হবে। আপনি নিচের যেকোনো উপাদান প্রিন্ট করলে দেখবেন যে তাদের সাথে একটি AutogradTensor যুক্ত আছে।"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# We encode everything\n",
    "data = data.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)\n",
    "target = target.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)\n",
    "model = model.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# ধাপ-৩ঃ ট্রেইনিং\n",
    "\n",
    "এখন আমরা সাধারণ টেনসর লজিক ব্যবহার করে মডেল ট্রেইন করব।"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "opt = optim.SGD(params=model.parameters(),lr=0.1).fix_precision()\n",
    "\n",
    "for iter in range(20):\n",
    "    # 1) erase previous gradients (if they exist)\n",
    "    opt.zero_grad()\n",
    "\n",
    "    # 2) make a prediction\n",
    "    pred = model(data)\n",
    "\n",
    "    # 3) calculate how much we missed\n",
    "    loss = ((pred - target)**2).sum()\n",
    "\n",
    "    # 4) figure out which weights caused us to miss\n",
    "    loss.backward()\n",
    "\n",
    "    # 5) change those weights\n",
    "    opt.step()\n",
    "\n",
    "    # 6) print our progress\n",
    "    print(loss.get().float_precision())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "লস (loss) আসলেই কমেছে!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## fixed precision এর প্রভাব (Impact of fixed precision)\n",
    "আপনার মনে হতে পারে যে সবকিছু এনক্রিপট করা কীভাবে হ্রাসমান লসের (loss) উপর প্রভাব ফেলছে। প্রকৃতপক্ষে, তাত্ত্বিক গণনা একই হওয়ায় প্রকৃত সংখ্যাগুলি এনক্রিপ্ট করা ট্রেইনিং এর খুব কাছাকাছি। আপনি এনক্রিপশন ছাড়াই এই একই মডেল চালিয়ে তা যাচাই করে দেখতে পারেন। এক্ষেত্রে আপনি __init__ এর সাহায্যে নিমক্ত মডেলের মতন নির্ণায়ক সূচনা (deterministic initialisation) নিশ্চিত করতে পারেন।:\n",
    "```\n",
    "with torch.no_grad():\n",
    "    self.fc1.weight.set_(torch.tensor([[ 0.0738, -0.2109],[-0.1579,  0.3174]], requires_grad=True))\n",
    "    self.fc1.bias.set_(torch.tensor([0.,0.1], requires_grad=True))\n",
    "    self.fc2.weight.set_(torch.tensor([[-0.5368,  0.7050]], requires_grad=True))\n",
    "    self.fc2.bias.set_(torch.tensor([-0.0343], requires_grad=True))\n",
    "```\n",
    "\n",
    "দশমিক সংখ্যাগুলোকে  fixed precision পূর্ণসংখ্যায় রূপান্তরিত করার ফলে মানের সামান্য তারতম্য দেখা যেতে পারে। সাধারণত   precision_fractional এর মান হচ্ছে ৩ এবং আপনি যদি তা ২ এ নামিয়ে আনেন তবে ক্লিয়ার টেক্সট ট্রেইনিং এর তারতম্য বেড়ে যাবে, অপরদিকে precision_fractional এর মান ৪ এ নিয়ে গেলে তা কমে যাবে। "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# অভিনন্দন - সম্প্রদায়ে যোগদানের এখনি সময়! (Congratulations!!! - Time to Join the Community!_\n",
    "\n",
    "এই নোটবুক টিউটোরিয়ালটি সম্পন্ন করার জন্য অভিনন্দন! আপনি যদি এটি উপভোগ করে থাকেন এবং তথ্যর গোপনীয়তা রক্ষা পূর্বক, বিকেন্দ্রীভূত মালিকানাধিন এআই (AI) ও এআই (AI) সাপ্লাই চেইন (ডেটা) এর এই আন্দোলনকে সমর্থন করেন, নিম্নোক্ত উপায়ে আমাদের পাশে থাকতে পারেন!\n",
    "\n",
    "### গিটহাবে PySyft কে স্টার দিন (Star PySyft on GitHub)\n",
    "\n",
    "আমাদের সম্প্রদায়কে সাহায্য করার সবচেয়ে সহজ উপায় হল গিটহাব রিপোসিটোরি গুলোতে ষ্টার দেয়া।\n",
    " এটি আমরা যে অসাধারণ সরঞ্জামগুলি তৈরি করছি তার সচেতনতা বাড়াতে সহায়তা করে।\n",
    "\n",
    "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "### আমাদের স্ল্যাকে যোগ দিন (Join our Slack!)\n",
    "\n",
    "সর্বশেষ আপডেট পাবার সর্বোত্তম উপায় হল আমাদের সম্প্রদায়ে যোগদান করা! এজন্য এই ফর্মটি পূরণ করতে পারেন।  [http://slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### একটি কোড প্রকল্পে যোগদান করুন! (Join a Code Project!)\n",
    "\n",
    "আমাদের সম্প্রদায়ে অবদান রাখার সর্বোত্তম উপায় হল কোড প্রকল্পে অবদান রাখা! আপনি PySyft Github Issues পেইজে গিয়ে ‘Projects’ এর জন্য ফিল্টার করতে পারেন। এটি আপনাকে শীর্ষস্থানীয় টিকেটগুলো দেখানোর মাধ্যমে আপনি কোন কোন প্রকল্পে কাজ করতে পারেন তার একটি ধারনা দিবে। যদি আপনি কোন প্রকল্পে যোগদান না করেই স্বল্প পর্যায়ের কোডিং করতে চান, তবে আপনি PySyft GitHub Issues পেইজে গিয়ে “Good First Issue” চিহ্নিত ইস্যুগুলো খুঁজে এক-কালিন কোন মিনি-প্রকল্প শুরু করতে পারেন!\n",
    "\n",
    "- [PySyft Projects](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
    "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### দান করা (Donate)\n",
    "\n",
    "আপনি যদি আমাদের কোডের প্রকল্পে অবদান রাখতে না পারেন কিন্তু তবুও আমাদের সমর্থন করতে চান, তবে আমাদের Open Collective এর Backer হতে পারেন। সকল অনুদান আমাদের ওয়েব হোসটিং এবং বিভিন্ন সাম্প্রদায়িক কার্যক্রম যেমন হ্যাকাথন, মিট-আপ ইত্যাদি কাজে ব্যয় হয়!\n",
    "\n",
    "- [Donate through OpenMined's Open Collective Page](https://opencollective.com/openmined)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  },
  "nbTranslate": {
   "displayLangs": [
    "*"
   ],
   "hotkey": "alt-t",
   "langInMainMenu": true,
   "sourceLang": "en",
   "targetLang": "fr",
   "useGoogleTranslate": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
